package cn.yeziji.forum.dao.impl;

import cn.yeziji.forum.annoataion.SaveCache;
import cn.yeziji.forum.bo.chatroom.ChatPrivateMsgBO;
import cn.yeziji.forum.bo.user.UserMsgBO;
import cn.yeziji.forum.bo.user.UserRegisterBO;
import cn.yeziji.forum.common.ForumAvatarMismatch;
import cn.yeziji.forum.common.enums.ForumCommonStatus;
import cn.yeziji.forum.common.ForumPageResult;
import cn.yeziji.forum.common.key.CommonKey;
import cn.yeziji.forum.common.key.DetailsCacheKey;
import cn.yeziji.forum.common.key.UserCacheKey;
import cn.yeziji.forum.converter.UserConverter;
import cn.yeziji.forum.dao.base.ForumUserBaseDao;
import cn.yeziji.forum.dao.intf.ForumFileDao;
import cn.yeziji.forum.dao.intf.ForumUserDao;
import cn.yeziji.forum.dao.iquery.UserQuery;
import cn.yeziji.forum.dao.iupdater.UserUpdater;
import cn.yeziji.forum.dto.user.EmailDTO;
import cn.yeziji.forum.dto.user.UserFocusOrFansListPagingDTO;
import cn.yeziji.forum.dto.user.UserRegisterDTO;
import cn.yeziji.forum.dto.user.UserUpdateDTO;
import cn.yeziji.forum.entity.ForumUserEntity;
import cn.yeziji.forum.exception.ForumException;
import cn.yeziji.forum.exception.UserException;
import cn.yeziji.forum.mapper.ForumUserMapper;
import cn.yeziji.forum.common.enums.status.UserStatus;
import cn.yeziji.forum.utils.*;
import cn.yeziji.forum.vo.user.UserMsgVO;
import cn.yeziji.forum.vo.user.UserUpdateVO;
import cn.yzj.common.CommonSymbol;
import cn.yzj.http.YzjHttp;
import cn.yzj.http.YzjHttpHeaders;
import cn.yzj.http.YzjHttpResult;
import cn.yzj.http.YzjSendConfig;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Repository;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 用户操作逻辑实现层
 *
 * @author gzkemays
 * @since 2021/12/21 15:54
 */
@Repository
@Slf4j
public class ForumUserDaoImpl extends ForumUserBaseDao implements ForumUserDao {
  @Resource ForumFileDao fileDao;
  @Resource ForumUserMapper userMapper;
  @Resource HttpServletRequest request;
  @Resource CacheUtils cache;

  @Resource(name = "customExecutor")
  ThreadPoolTaskExecutor threadPoolTaskExecutor;

  @Value("${openapi.auth}")
  String auth;

  @Value("${openapi.url}")
  String url;

  @Override
  public void registerSendEmail(EmailDTO dto) {
    sendEmailCode(dto);
  }

  @PostConstruct
  public void init() {
    this.cache = this.cache.closeCaffeineCache();
  }

  @Override
  public ForumUserEntity selectUserByUserName(String username) {
    String cacheKey = UserDaoCacheKey.get0NameEntityCacheKey(username);
    Object obj = cache.get(cacheKey);
    if (obj == null) {
      ForumUserEntity one = userMapper.findOne(UserQuery.selectUserByUserNameQuery(username));
      if (one != null) {
        cache.set(cacheKey, one, 1, TimeUnit.DAYS);
      }
      return one;
    }
    return (ForumUserEntity) obj;
  }

  @Override
  public ForumUserEntity selectUserByNickName(String nickname) {
    String cacheKey = UserDaoCacheKey.getNameEntityCacheKey(nickname);
    Object obj = cache.get(cacheKey);
    if (obj == null) {
      ForumUserEntity one = userMapper.findOne(UserQuery.selectUserByNickNameQuery(nickname));
      if (one == null) {
        throw new UserException(UserStatus.USER_IS_NOT_FOUND);
      }
      cache.set(cacheKey, one, 1, TimeUnit.DAYS);
      return one;
    }
    return (ForumUserEntity) obj;
  }

  @Override
  public ForumPageResult<UserMsgVO> getFocusOrFansUserMsg(UserFocusOrFansListPagingDTO pagingDTO) {
    boolean fans = pagingDTO.isFans(), focus = pagingDTO.isFocus();
    if (!fans && !focus || fans && focus) {
      // 不能两者同时为 false 或同时为 true
      throw new ForumException(ForumCommonStatus.DATA_ERROR);
    }
    Integer userId = JwtOperaUtils.getUserIdIfZero(request);
    String nickname = pagingDTO.getNickname();
    ForumUserEntity userEntity;
    // nickname 为空，根据 token 获取自身信息，fans 为 false 那么 focus 必然为 true
    String cacheKey = fans ? UserCacheKey.USER_FANS_CACHE : UserCacheKey.USER_FOCUS_CACHE;
    if (nickname == null) {
      throw new ForumException(ForumCommonStatus.DATA_ERROR);
    } else {
      userEntity = selectUserByNickName(nickname);
      cacheKey += userEntity.getUsername() + "::" + userId;
    }
    String hashKey = pagingDTO.getPage() + "-" + pagingDTO.getLimit();
    Object obj = cache.getByHash(cacheKey, hashKey);
    if (obj == null) {
      // 凑齐 ids
      String split = fans ? userEntity.getFansIds() : userEntity.getFocusIds();
      pagingDTO.setUserIds(split.split(CommonSymbol.COMMA));
      List<UserMsgBO> userMsgBOS =
          mapper.listPoJos(UserMsgBO.class, UserQuery.selectFocusOrFansUserMsg(pagingDTO));
      ForumPageResult<UserMsgVO> pageResult =
          new ForumPageResult<>(UserMsgBO.buildUserMsgListVo(userMsgBOS, userId), pagingDTO);
      cache.setHash(cacheKey, hashKey, pageResult, 1, TimeUnit.DAYS);
      return pageResult;
    }
    return (ForumPageResult<UserMsgVO>) obj;
  }

  @Override
  public ForumPageResult<UserMsgVO> getFocusAndFansUserMsg(UserFocusOrFansListPagingDTO pagingDTO) {
    Integer userId = JwtOperaUtils.getUserIdIfZero(request);
    ForumPageResult<UserMsgVO> focus = getFocus(userId, pagingDTO);
    ForumPageResult<UserMsgVO> fans = getFans(userId, pagingDTO);
    List<UserMsgVO> focusData = focus.getData();
    List<UserMsgVO> fansData = fans.getData();
    Set<UserMsgVO> set = new HashSet<>();
    set.addAll(focusData);
    set.addAll(fansData);
    pagingDTO.total(focus.getTotal() + fans.getTotal());
    return new ForumPageResult<>(set, pagingDTO);
  }

  @Override
  public ChatPrivateMsgBO getByToAndFromUserMsg(String to, String from) {
    ChatPrivateMsgBO bo = new ChatPrivateMsgBO();
    String toCacheKey = UserDaoCacheKey.getNameEntityCacheKey(to);
    String fromCacheKey = UserDaoCacheKey.getNameEntityCacheKey(from);
    Object toObj = cache.get(toCacheKey);
    Object fromObj = cache.get(fromCacheKey);
    ForumUserEntity fromEntity;
    if (fromObj != null) {
      fromEntity = (ForumUserEntity) fromObj;
    } else {
      fromEntity = selectUserByNickName(from);
    }
    bo.setFrom(fromEntity.getNickname());
    bo.setFromAvatar(fromEntity.getAvatar());
    ForumUserEntity toEntity;
    if (toObj != null) {
      toEntity = (ForumUserEntity) toObj;
    } else {
      toEntity = selectUserByNickName(to);
    }
    bo.setTo(toEntity.getNickname());
    bo.setToAvatar(toEntity.getAvatar());
    return bo;
  }

  @Override
  public UserMsgVO getUserMsg(String nickname) {
    Integer userId = JwtOperaUtils.getUserIdIfZero(request);
    String cacheKey;
    if (nickname == null) {
      throw new ForumException(ForumCommonStatus.DATA_ERROR);
    } else {
      ForumUserEntity userEntity = selectUserByNickName(nickname);
      cacheKey =
          UserCacheKey.USER_ENTITY_BY_OTHER_USERID_CACHE + userEntity.getUsername() + "::" + userId;
    }
    Object obj = cache.get(cacheKey);
    UserMsgVO userMsgVO;
    if (obj == null) {
      // nickname 存在，获取 request 用户与 nickname 用户的关系
      Optional<UserMsgBO> one =
          mapper.findOne(UserMsgBO.class, UserQuery.staticsUserMsgVoById(null, nickname));
      if (one.isPresent()) {
        userMsgVO = one.get().buildUserMsgVO(userId);
        cache.set(cacheKey, userMsgVO, 7, TimeUnit.DAYS);
        return userMsgVO;
      }
      throw new UserException(UserStatus.USER_DATA_EXCEPTION);
    }
    return (UserMsgVO) obj;
  }

  @Override
  public List<UserMsgVO> getUserMsgList(List<String> nickname) {
    return UserConverter.INSTANCE.convertToUserMsgByEntities(
        mapper.listEntity(UserQuery.selectUserByNickNames(nickname)));
  }

  @Override
  public List<UserMsgVO> getFocusAndFansUserMsg() {
    Integer userId = JwtOperaUtils.getUserIdByRequest(request);
    ForumUserEntity entity = userMapper.findById(userId);
    Set<Integer> ids = new HashSet<>();
    List<Integer> fansIds =
        StrUtils.strToList(entity.getFansIds(), CommonKey.LIST_STR_SPILT, Integer.class);
    List<Integer> focusIds =
        StrUtils.strToList(entity.getFocusIds(), CommonKey.LIST_STR_SPILT, Integer.class);
    ids.addAll(fansIds);
    ids.addAll(focusIds);
    if (!ids.isEmpty()) {
      List<UserMsgVO> vos = new ArrayList<>();
      List<ForumUserEntity> entities = userMapper.listByIds(ids);
      for (ForumUserEntity userEntity : entities) {
        List<Integer> userFans =
            StrUtils.strToList(userEntity.getFansIds(), CommonKey.LIST_STR_SPILT, Integer.class);
        List<Integer> userFocus =
            StrUtils.strToList(userEntity.getFocusIds(), CommonKey.LIST_STR_SPILT, Integer.class);
        if (userFans.contains(userId)) {
          UserMsgVO userMsgVO = UserConverter.INSTANCE.convertToUserMsgByEntity(userEntity);
          userMsgVO.setFans(true);
          vos.add(userMsgVO);
        }
        if (userFocus.contains(userId)) {
          UserMsgVO userMsgVO = UserConverter.INSTANCE.convertToUserMsgByEntity(userEntity);
          userMsgVO.setFocus(true);
          vos.add(userMsgVO);
        }
      }
      return vos;
    }
    return ListsCollect.emptyList();
  }

  @Override
  public List<ForumUserEntity> getFansUserMsgById(Integer userId) {
    ForumUserEntity userEntity = mapper.findById(userId);
    String fansIds = userEntity.getFansIds();
    String[] split = fansIds.split(CommonSymbol.COMMA);
    if (split.length > 0) {
      return mapper.listByIds(split);
    }
    return new ArrayList<>();
  }

  @Override
  public ForumUserEntity registerUser(UserRegisterBO bo) {
    bo.setEmail("1538213123@1312.com");
    ForumUserEntity entity = UserConverter.INSTANCE.convertUserEntityByRegisterBo(bo);
    checkRegister(entity);
    userMapper.insert(entity);
    return entity;
  }

  @Override
  public ForumUserEntity login(String username, String password) {
    return userMapper.findOne(UserQuery.selectUserByLogin(username, password));
  }

  @Override
  public void register(UserRegisterDTO dto) {
    checkRegister(dto);
    userMapper.insert(UserConverter.INSTANCE.userRegConvertToEntity(dto));
  }

  /**
   * 头像上传主方法
   *
   * @author lzc, gzkemays
   * @since 2022/3/28
   * @param dto 通过前端获取的头像文件,用户名信息进行上传头像
   * @return cn.yeziji.forum.dto.user.UserUploadDTO
   */
  @Override
  public UserUpdateVO update(UserUpdateDTO dto) {
    Integer userId = JwtOperaUtils.getUserIdByRequest(request);
    String tokenByRequest = JwtOperaUtils.getTokenByRequest(request);
    // 关注操作
    if (dto.getFocus() != null) {
      try {
        CompletableFuture<UserUpdateDTO> supplyAsync =
            CompletableFuture.supplyAsync(() -> handlerFocus(dto, userId), threadPoolTaskExecutor);
        UserUpdateDTO userUpdateDTO = supplyAsync.get();
        supplyAsync.thenRunAsync(
            () -> validateRemoveFocusCacheHandler(userUpdateDTO, tokenByRequest));
        return UserConverter.INSTANCE.convertUploadVoByDto(userUpdateDTO);
      } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
      }
    }
    //    Integer userId = dto.getUserId();
    ForumUserEntity userEntity = selectById(userId);
    CompletableFuture<UserUpdateDTO> supplyAsync =
        CompletableFuture.supplyAsync(
            () -> {
              dto.setUserId(userId);
              // 判断更新锁
              String avatarLock = UserCacheKey.USER_UPDATE_LOCK + "avatar" + "::" + dto.getUserId();
              if (dto.getFile() != null) {
                if (cache.hasKey(avatarLock)) {
                  throw new UserException(UserStatus.USER_UPDATE_LOCK);
                }
                dto.setAvatar(fileDao.saveFile(dto.getFile(), ForumFileDao.USER_AVATAR));
              }
              String nicknameLock = UserCacheKey.USER_UPDATE_LOCK + "nickname" + "::" + userId;
              if (dto.getNickname() != null) {
                if (cache.hasKey(nicknameLock)) {
                  throw new UserException(UserStatus.USER_UPDATE_LOCK);
                }
              }
              String descLock = UserCacheKey.USER_UPDATE_LOCK + "desc" + "::" + dto.getUserId();
              if (dto.getDesc() != null) {
                if (cache.hasKey(descLock)) {
                  throw new UserException(UserStatus.USER_UPDATE_LOCK);
                }
              }
              // 判断用户当前的用户名是否唯一
              if (dto.getNickname() != null) {
                int count =
                    userMapper.count(
                        UserQuery.selectUserByNickNameQuery(dto.getNickname(), userId));
                if (count >= 1) {
                  throw new UserException(UserStatus.NON_ONE_NICK_NAME);
                }
              }
              // 判断当前类型是否是支持的图片类型
              if (dto.getFile() != null) {
                MultipartFile file = dto.getFile();
                String contentType = file.getContentType();
                if (!ForumAvatarMismatch.avatarMatch(contentType)) {
                  throw new UserException(UserStatus.USER_AVATAR_TYPE_MISMATCH);
                }
              }
              // 更新数据
              userMapper.updateBy(UserUpdater.userUploadUpdater(dto));
              // 施加更新锁
              if (dto.getNickname() != null) {
                cache.set(nicknameLock, userId, 7, TimeUnit.DAYS);
              }
              if (dto.getDesc() != null) {
                cache.set(descLock, userId, 7, TimeUnit.DAYS);
              }
              if (dto.getFile() != null) {
                cache.set(avatarLock, userId, 7, TimeUnit.DAYS);
              }
              return dto;
            },
            threadPoolTaskExecutor);
    // ---- 处理缓存 ----
    supplyAsync.thenRunAsync(
        () -> {
          removeUpdateCacheHandler(userEntity, userId, tokenByRequest);
        },
        threadPoolTaskExecutor);
    // 处理异常
    try {
      supplyAsync.join();
      UserUpdateDTO userUpdateDTO = supplyAsync.get();
      return UserConverter.INSTANCE.convertUploadVoByDto(userUpdateDTO);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    throw new ForumException(ForumCommonStatus.UNKNOWN_ERROR);
  }

  @Override
  @SaveCache(UserCacheKey.USER_COUNT)
  public int getUserCount() {
    Object obj = cache.get(UserCacheKey.USER_COUNT);
    if (obj == null) {
      return mapper.count(query().where.delete().isFalse().end());
    }
    return (int) obj;
  }

  private ForumPageResult<UserMsgVO> getFocus(
      Integer userId, UserFocusOrFansListPagingDTO pagingDTO) {
    String nickname = pagingDTO.getNickname();
    String focusCacheKey = UserCacheKey.USER_FOCUS_CACHE;
    // 查看是否通过 getFocusOrFansUserMsg 构建过缓存对象
    if (nickname != null) {
      ForumUserEntity userEntity = selectUserByNickName(nickname);
      focusCacheKey += userEntity.getUsername() + "::" + userId;
    } else {
      focusCacheKey += userId;
    }
    String hashKey = pagingDTO.getPage() + "-" + pagingDTO.getLimit();
    Object focusMsgVos = cache.getByHash(focusCacheKey, hashKey);
    if (focusMsgVos == null) {
      pagingDTO.setFocus(true);
      pagingDTO.setFans(false);
      focusMsgVos = getFocusOrFansUserMsg(pagingDTO);
    }
    return (ForumPageResult<UserMsgVO>) focusMsgVos;
  }

  private ForumPageResult<UserMsgVO> getFans(
      Integer userId, UserFocusOrFansListPagingDTO pagingDTO) {
    String nickname = pagingDTO.getNickname();
    String fansCacheKey = UserCacheKey.USER_FANS_CACHE;
    // 查看是否通过 getFocusOrFansUserMsg 构建过缓存对象
    if (nickname != null) {
      ForumUserEntity userEntity = selectUserByNickName(nickname);
      fansCacheKey += userEntity.getUsername() + "::" + userId;
    } else {
      fansCacheKey += userId;
    }
    String hashKey = pagingDTO.getPage() + "-" + pagingDTO.getLimit();
    Object focusMsgVos = cache.getByHash(fansCacheKey, hashKey);
    if (focusMsgVos == null) {
      pagingDTO.setFocus(false);
      pagingDTO.setFans(true);
      focusMsgVos = getFocusOrFansUserMsg(pagingDTO);
    }
    return (ForumPageResult<UserMsgVO>) focusMsgVos;
  }
  /**
   * 发送验证码至邮箱
   *
   * @param dto 邮箱配置类
   */
  private void sendEmailCode(EmailDTO dto) {
    // 判断时间戳是否属于波动之内
    if (!TimeUtils.timestampBetweenFluctuations(
        Long.parseLong(dto.getTimestamp()), TIMESTAMP_FLUCTUATIONS)) {
      throw new UserException(UserStatus.TIME_STAMP_IS_MISTAKE);
    }
    String email = dto.doEmail();
    // 缓存如果未过期,则意味邮件验证码发送过于频繁
    if (cache.get(email) != null) {
      throw new UserException(UserStatus.EMAIL_CODE_IS_FAST);
    }
    // 检查 email 是否已经被注册
    if (userMapper.count(UserQuery.selectUserByEmail(email)) > 0) {
      throw new UserException(UserStatus.USER_EMAIL_IS_NOT_ONLY);
    }
    dto.buildEmailCodeDto();
    YzjHttpResult result =
        YzjHttp.createPost(url + CommonKey.EMAIL)
            .dataObj(dto)
            .yzjHeaders(
                YzjHttpHeaders.builder().key(CommonKey.OPEN_API_AUTH_KEY).value(this.auth).build())
            .config(YzjSendConfig.start().postJson().json().end())
            .send();
    JSONObject json = result.getJson();
    if (Objects.nonNull(json.get(CommonKey.OPEN_API_DATA_KEY))) {
      String code = json.getString(CommonKey.OPEN_API_DATA_KEY);
      cache.set(email, code, 1, TimeUnit.MINUTES);
      log.info("验证码 --> {}", code);
    } else {
      throw new UserException(UserStatus.USER_EMAIL_SEND_FAIL);
    }
  }

  /**
   * 检查注册
   *
   * <ul>
   *   执行无异常则通过
   *   <li>用户名唯一
   *   <li>用户名长短符合规范
   *   <li>密码符合规范
   *   <li>邮箱符合规范
   *   <li>核对邮箱的验证码是否过期以及是否正确对应
   * </ul>
   *
   * @param dto 注册值对象
   */
  private void checkRegister(UserRegisterDTO dto) {
    String username = dto.getUsername().trim();
    String password = dto.getPassword();
    String truthPassword = dto.getTruthPassword();
    String email = dto.getEmail();
    String code = dto.getCode();
    String cacheCode = cache.get(email);
    ForumUserEntity entity = this.selectUserByUserName(username);
    // 校验账号是否已被注册
    if (Objects.nonNull(entity)) {
      throw new UserException(UserStatus.USER_NAME_RE_REG);
    }
    // 检查账号是否过短
    if (username.length() < USERNAME_MIN_LENGTH) {
      throw new UserException(UserStatus.USER_NAME_IS_SHORT);
    }
    // 检查账号是否过长
    if (username.length() > USERNAME_MAX_LENGTH) {
      throw new UserException(UserStatus.USER_NAME_IS_TO_LONG);
    }
    // 检查密码
    if (password.length() < PASSWORD_MIN_LENGTH) {
      throw new UserException(UserStatus.USER_PASSWORD_IS_SHORT);
    }
    // 检查密码是否一致
    if (!password.equals(truthPassword)) {
      throw new UserException(UserStatus.USER_PASSWORD_IS_DIFFERENT);
    }
    // 检查邮箱
    if (!StrUtils.isEmail(email)) {
      throw new UserException(UserStatus.USER_EMAIL_FORMAT_ERROR);
    }
    // 检查验证码
    if (Objects.isNull(cacheCode)) {
      throw new UserException(UserStatus.EMAIL_CODE_IS_EXPIRED);
    } else if (!code.equals(cacheCode)) {
      throw new UserException(UserStatus.EMAIL_CODE_IS_MISTAKE);
    }
  }
  /**
   * 注册检查
   *
   * @param entity 检查实体数据
   * @deprecated 已摒弃该登录注册方案的检验方式
   */
  private void checkRegister(ForumUserEntity entity) {
    String username = entity.getUsername().trim();
    String password = entity.getPassword();

    if (username.length() < USERNAME_MIN_LENGTH) {
      throw new UserException(UserStatus.USER_NAME_IS_SHORT);
    }
    if (username.length() > USERNAME_MAX_LENGTH) {
      throw new UserException(UserStatus.USER_NAME_IS_TO_LONG);
    }
    if (password.length() < PASSWORD_MIN_LENGTH) {
      throw new UserException(UserStatus.USER_PASSWORD_IS_SHORT);
    }
    entity.setNickname(entity.getUsername());
  }

  private UserUpdateDTO handlerFocus(UserUpdateDTO dto, Integer userId) {
    log.info("Thread execute handlerFocus name -> {} ", Thread.currentThread().getName());
    dto.setUserId(userId);
    // 判断是否发生了关注操作，如果发生了关注操作，那么只需要注重关注的业务即可
    if (dto.getFocus() != null) {
      // 根据 nickname 关注对象和粉丝 id 查询并作为 map，一般而言，只有 2 个数据
      Map<Integer, ForumUserEntity> collect =
          this.listEntity(UserQuery.selectUserByNickNameOrOtherUserId(dto.getFocus(), userId))
              .stream()
              .collect(Collectors.toMap(ForumUserEntity::getId, Function.identity()));
      // 必然不大于 2
      if (collect.size() > 2) {
        throw new UserException(UserStatus.USER_DATA_EXCEPTION);
      }
      ForumUserEntity currentUser = null, focusUser = null;
      for (Map.Entry<Integer, ForumUserEntity> entry : collect.entrySet()) {
        if (entry.getKey().equals(userId)) {
          currentUser = entry.getValue();
        } else {
          focusUser = entry.getValue();
        }
      }
      if (currentUser == null || focusUser == null) {
        throw new UserException(UserStatus.USER_IS_NOT_FOUND);
      }
      // 获取当前用户的信息，以及用户的关注用户的 id 列表
      List<String> currentUserFocusIds =
          StrUtils.strToList(currentUser.getFocusIds(), CommonKey.LIST_STR_SPILT, String.class);
      // 获取关注对象的用户信息，以及关注对象的粉丝 id 列表
      String id = focusUser.getId().toString();
      List<String> fansIds =
          StrUtils.strToList(focusUser.getFansIds(), CommonKey.LIST_STR_SPILT, String.class);
      // 更新关注列表
      if (currentUserFocusIds.contains(id)) {
        // 如果关注列表中有当前用户，那么就是取关操作
        dto.setToFocus(false);
        currentUserFocusIds.remove(id);
        fansIds.remove(userId.toString());
      } else {
        dto.setToFocus(true);
        currentUserFocusIds.add(id);
        fansIds.add(userId.toString());
      }
      focusUser.setFansIds(StrUtils.listToStr(fansIds, CommonKey.LIST_STR_SPILT));
      // 更新粉丝列表
      updateById(focusUser);
      // 将最新的关注列表插入 dto 中
      dto.setFocusIds(StrUtils.listToStr(currentUserFocusIds, CommonKey.LIST_STR_SPILT));
      // 更新用户关注列表
      userMapper.updateBy(UserUpdater.userUploadUpdater(dto));
      return dto;
    }
    return null;
  }

  private void validateRemoveFocusCacheHandler(UserUpdateDTO dto, String token) {
    log.info(
        "Thread execute validateRemoveFocusCacheHandler name -> {} ",
        Thread.currentThread().getName());
    if (dto == null) {
      throw new UserException(UserStatus.USER_DATA_EXCEPTION);
    }
    String userNameByToken = JwtOperaUtils.getUserNameByToken(token);
    Integer idByToken = JwtOperaUtils.getIdByToken(token);
    ForumUserEntity entity = this.selectUserByNickName(dto.getFocus());
    cache.remove(UserDaoCacheKey.getNameEntityCacheKey(dto.getFocus()));
    // 删除关注列表的缓存以及关注人的粉丝列表缓存
    cache.blurPrefixRemove(UserCacheKey.USER_FOCUS_CACHE + userNameByToken);
    cache.blurPrefixRemove(UserCacheKey.USER_FANS_CACHE + entity.getUsername());
    // 删除个人页面的关注
    cache.remove(
        UserCacheKey.USER_ENTITY_BY_OTHER_USERID_CACHE + entity.getUsername() + "::" + idByToken);
    // 删除个人缓存
    cache.remove(UserCacheKey.USER_ENTITY_BY_USERNAME_CACHE + userNameByToken);
    cache.remove(UserCacheKey.USER_ENTITY_BY_NICKNAME_CACHE + userNameByToken);
  }

  private void removeUpdateCacheHandler(ForumUserEntity userEntity, Integer userId, String token) {
    log.info(
        "Thread execute removeUpdateCacheHandler name -> {} ", Thread.currentThread().getName());
    // 因为文章具备用户的信息，因此，当用户更新数据后，文章的缓存进行删除，确保信息与文章保持一致。
    cache.blurRemoveHash(DetailsCacheKey.CACHE_PAGE_HASH_KEY, "-(" + userId + ")");
    // 删除统计缓存
    cache.remove(
        UserCacheKey.USER_ENTITY_BY_OTHER_USERID_CACHE + userEntity.getUsername() + "::" + userId);
    // 删除 username 和 nickname 的缓存
    cache.remove(UserCacheKey.USER_ENTITY_BY_USERNAME_CACHE + userEntity.getUsername());
    cache.remove(UserCacheKey.USER_ENTITY_BY_NICKNAME_CACHE + userEntity.getNickname());
  }
}
